<?php
namespace core;

use Exception;
/**
 * 加载框架使用
 */
class App
{
	// 模块
	private $module;
	// 控制器
	private $controller;
	// 动作
	private $action;
	// 根据命名空间的前缀部分，获取类库文件目录
	private $namespacePath;
	// 类文件目录文件
	private $classFile;
	// 定义访问的类名
	private $class;


	/**
	 * 1、 php-fpm模式
	 */
	public function run($mode=1){
		$self = $_SERVER['PHP_SELF'];
		// 从根目录运行
		if(IS_ROOT){
			$start = newstripos($self,'/',2);
		}else{
			// 嵌入到其他项目中做为一个扩展子模块
			$start = newstripos($self,'/',3);
		}
		if($start>0){
			$argment =  substr($self,$start+1);
		}else{
			$argment = '';
		}
		$coreConfig = self::_loadCoreConfig();
		if($argment && $argments = explode(URL_DELIMITER, $argment)){
			$this->module = $argments[0] ?? ($coreConfig['default']['module'] ?? '');
			$this->controller = $argments[1] ?? ($coreConfig['default']['controller'] ?? '');
			$this->action =  $argments[2] ?? ($coreConfig['default']['action'] ?? '');
		}else{
			$this->module = $coreConfig['default']['module'] ?? ''; // 目录
			$this->controller =  $coreConfig['default']['controller'] ?? '';
			$this->action =  $coreConfig['default']['action'] ?? '';
		}
		
		
		$this->_checkModule(); // 验证
		spl_autoload_register([$this,'spl'],true); // 自动加载
		$controller =  "app\\{$this->module}\\{$this->controller}";
		$App = new $controller();		
		$this->_action($App); // 启动结束
	}

	public function cli(){
		// 待开发
	}

	/**
	 * 加载核心配置文件
	 * @return [type] [description]
	 */
	private static function _loadCoreConfig(){
		return require_once(CONFIG_PATH . '/core.php');
	}

	/**
	 * 验证 m c a
	 * @return [type] [description]
	 */
	private  function _checkModule(){
		// 判断模块目录
		if($this->module == ''  || !is_dir(CONTROLLER_PATH.'/'.$this->module)){
			throw new Exception("module not found", 101);
		}
		if($this->controller == ''){
			throw new Exception("controller not found", 102);
		}
		if($this->action == ''){
			throw new Exception("method not found", 103);
		}
		$this->module = strtolower($this->module);
		$this->controller = ucfirst($this->controller);
	}

	/**
	 * 通过 spl 方法运行 控制器动作
	 */
	public function spl($class){
		static $i=1;
		$this->getNamespaceDir($class); // 获取类名
		$this->classFile =   $this->namespacePath . $this->class .'.php';
		require_once $this->classFile;
		// 判断直接访问的类是否存在
		if(!is_file($this->classFile)){
			throw new Exception($this->class ." Controller File Not Found", 104);			
		}
		
		set_error_handler([$this,'errorHandle'],E_ALL);	// 自定义错误	
		$controller = $this->genericController();
		if(!class_exists( $controller )){
			// throw new Exception($controller . " Controller Not Found", 105);
		}		
	}

	/**
	 * 访问控制器
	 * @return [type] [description]
	 */
	private function _action($Controller){
		if(!is_callable([$Controller,$this->action])){
			throw new Exception($this->action." Method not found", 106);			
		}		
		call_user_func([$Controller, $this->action]);
	}

	/**
	 * 生成可访问的结构
	 */
	private function genericController(){
		$controller =  "app\\{$this->module}\\{$this->controller}";
		return get_parent_class($controller);
	}

	/**
	 *  捕获错误
	 */
	public function errorHandle($errno, $errstr, $errfile, $errline){
		throw new Exception("ERROR : ".$errstr . " ~~~ ERRNO :". $errno . " File :".$errfile . " Line :".$errline, 1);		
	}

	/**
	 * 根据命名空间 获取第一级目录名称
	 * @return void
	 */
	public function getNamespaceDir($class){
		$class = str_replace('\\','/',$class);
		$namespaceSuffix = substr($class ,0 , strpos($class,'/')); // 命名空间拼接类的前缀
		preg_match("|/([^^]*?)/|u", $class, $matches);
		$namespaceCenter = isset($matches[1]) ? $matches[1] : '';// 命名空间 去掉前缀 和 后缀保留的中间部分
		$use = substr($class,0,strrpos($class,'/')+1); 
		// 业务根目录 controller 目录下
		if($namespaceSuffix == 'app'){
			if($namespaceCenter){
				$this->namespacePath = CONTROLLER_PATH .'/'.$namespaceCenter .'/';
			}else{
				$this->namespacePath = CONTROLLER_PATH .'/';
			}			
		}elseif(is_dir(ROOT_PATH . '/'. $use)){
			// 从根目录开始的命名空间
			$this->namespacePath = ROOT_PATH . '/'.$use;
		}else{
			if($namespaceCenter){
				$this->namespacePath = CORE_PATH . '/'.$namespaceSuffix.'/' . $namespaceCenter .'/';
			}else{
				$this->namespacePath = CORE_PATH . '/'.$namespaceSuffix.'/'; // 命名空间前缀
			}			
		}
		$this->class = substr($class,strrpos($class,'/')+1); // 纯类名
	}
}